%%
%% 负责编码解码Erlang的消息，并管理一个套接字上的通信
%%

%% Protocol
%%  To the controlling process
%% 		{chan, MM, Term}
%%		{chan_closed, MM}
%% 	From any process
%% 		{send, Term}
%% 		close


-module(lib_chan_mm).

%% TCP Middle man
%% Models the interface to gen_tcp

-export([loop/2, send/2, close/1, controller/2, set_trace/2, trace_with_tag/2]).

send(Pid, Terms) 		-> Pid ! {send, Terms}.
close(Pid) 				-> Pid ! close.
controller(Pid, Pid1) 	-> Pid ! {setController, Pid1}.
set_trace(Pid, X)		-> Pid ! {trace, X}.

trace_with_tag(Pid, Tag) ->
	set_trace(Pid, {true, fun(Msg) -> io:format("MM:~p ~p~n",[Tag, Msg]) end }).

%% 这个Pid就是Controller
loop(Socket, Pid) ->
	process_flag(trap_exit, true),
	loop1(Socket, Pid, false).

%% 对于服务器端来说，这个Pid就是Controller,它会向Controlle发送消息，然后Controller会向服务器进程S发送消息。
%% 那么接下来要看的是，谁会向这个用了loop1的进程发消息
%% Trace是一个boolean
loop1(Socket, Pid, Trace) ->
	receive
		{tcp, Socket, Bin} ->
			io:format("Pid receive = ~p~n",[Pid]),
			Term = binary_to_term(Bin),
			trace_it(Trace, {socketReceive, Term}),
    		io:format("receive msg =~p~n",[Term]),
			Pid ! {chan, self(), Term},
			loop1(Socket, Pid, Trace);	% 这里的Pid被我写成了slef().导致程序一直运行出错，直接发送消息给了S,而不是Controller
	    	% 我说怎么消息不知道跑到哪里去了。 	总结教训：要注意进程通信的Pid
		{tcp_closed, Socket} ->
			trace_it(Trace, socketClosed),
			Pid ! {chan_closed, self()};
		{'EXIT', Pid, Why} ->
			trace_it(Trace, {controllingProcessExit, Why}),
			gen_tcp:close(Socket);
		{setController, Pid1} ->
			trace_it(Trace, {changedController, Pid}),
			loop1(Socket, Pid1, Trace);
		{trace, Trace1} ->
			trace_it(Trace, {setTrace, Trace1}),
			loop1(Socket, Pid, Trace);
		close ->
			gen_tcp:close(Socket);
		{send, Term} ->
			trace_it(Trace, {sendingMessage, Term}),
    		io:format("send msg =~p~n",[Term]),
			io:format("Pid send = ~p~n",[Pid]),
			gen_tcp:send(Socket, term_to_binary(Term)),	% 这一句一般会跳到另一端的{tcp, Socket, Bin}这里来匹配
			loop1(Socket, Pid, Trace);
		UUg ->
			io:format("lib_chan_mm:protocol error:~p~n",[UUg]),
			% Pid ! {chan, self(), Term},
			loop1(Socket, Pid, Trace)
	end.



trace_it(false, _) 			-> void;
trace_it({true, F}, M) 		-> F(M).










